﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using WindowsFormsApplication1.RebornLogin;
using System.IO;
using System.Xml;

namespace WindowsFormsApplication1.TellRequests
{
    public class TellRequestPS
    {
        public ServerSocketData _requesterServer;

        private List<TellRequestResultPS> results = new List<TellRequestResultPS>();
        private Timer requestTimeout = new Timer(10000);

        public string tellGuid;
        public string fromName; 
        public string toName;
        public string message;
        public string itemLinksXml;

        public TellRequestPS(ServerSocketData requesterServer)
        {
            _requesterServer = requesterServer;
            requestTimeout.AutoReset = false;
            requestTimeout.Elapsed += new ElapsedEventHandler(requestTimeout_Elapsed);
            requestTimeout.Start();
        }

        public bool result
        {
            get
            {
                lock (results)
                {
                    foreach (TellRequestResultPS result in results)
                    {
                        if (result.messageSuccessfull == true)
                            return true;
                    }
                }
                return false;
            }
        }

        public void processResult(ServerSocketData ssd, bool messageSuccessfull)
        {
            bool allResultsRecieved = true;
            lock (results)
            {
                foreach (TellRequestResultPS result in results)
                {
                    if (result.server == ssd)
                    {
                        result.hasResponded = true;
                        result.messageSuccessfull = messageSuccessfull;
                        if (messageSuccessfull == true)
                        {
                            allResultsRecieved = true;
                            break;
                        }
                    }
                    if (result.hasResponded == false)
                        allResultsRecieved = false;
                }
            }
            if (allResultsRecieved == true)
            {
                //Pass the request back up to the manager for completion, so it can remove this request from the queue
                Managers.tellManager.completeRequest(this);
            }
        }

        public void completeRequest()
        {
            this.requestTimeout.Stop();
            this.requestTimeout.Dispose();

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            //Sending the origional request result back, so origin is WS
            xmldoc.WriteStartElement("tellrequestresultWS");
            xmldoc.WriteAttributeString("tellguid", tellGuid.ToString());
            xmldoc.WriteAttributeString("fromname", fromName.ToString());
            xmldoc.WriteAttributeString("toname", toName.ToString());
            xmldoc.WriteAttributeString("messagesuccessfull", result.ToString());

            //No need to send the message text back to the origin server.
            //World server has recorded the origional message. The request will get matched by the tellguid. 
            
            //xmldoc.WriteStartElement("txt");
            //xmldoc.WriteRaw(Managers.escapeXmlText(message));
            //xmldoc.WriteEndElement();

            //xmldoc.WriteRaw(itemLinksXml);

            xmldoc.WriteEndElement();
            xmldoc.Flush();
            xmldoc.Close();
            stringWriter.Flush();
            string xmlMessage = stringWriter.ToString();

            try
            {
                byte[] byData = System.Text.Encoding.ASCII.GetBytes(xmlMessage + "\0");
                this._requesterServer.socket.Send(byData);
            }
            catch { }
        }

        public void sendRequests()
        {
            List<ServerSocketData> servers = Managers.socketConnectionsManager.GetServerSocketsCpy();
            servers.Remove(_requesterServer);

            if (servers.Count == 0)
            {
                Managers.tellManager.completeRequest(this);
                return;
            }

            //Build list of results we expect to recieve
            foreach (ServerSocketData server in servers)
            {
                TellRequestResultPS result = new TellRequestResultPS();
                result.server = server;
                results.Add(result);
            }

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);
            xmldoc.WriteStartElement("tellrequestPS");
            xmldoc.WriteAttributeString("tellguid", tellGuid.ToString());
            xmldoc.WriteAttributeString("fromname", fromName.ToString());
            xmldoc.WriteAttributeString("toname", toName.ToString());

            xmldoc.WriteStartElement("txt");
            xmldoc.WriteRaw(Managers.escapeXmlText(message));
            xmldoc.WriteEndElement();

            xmldoc.WriteRaw(itemLinksXml);

            xmldoc.WriteEndElement();
            xmldoc.Flush();
            xmldoc.Close();
            stringWriter.Flush();
            string xmlMessage = stringWriter.ToString();

            //Send request out to all servers
            foreach (ServerSocketData ssd in servers)
            {
                //If send to this server failed, remove its expected result
                if (SocketConnectionsManager.sendToServer(ssd, xmlMessage) == false)
                {
                    lock (results)
                    {
                        foreach (TellRequestResultPS result in results)
                        {
                            if (result.server == ssd)
                            {
                                results.Remove(result);
                                break;
                            }
                        }
                        //If the send took a while to fail, we may have already gotten all responses, so we need to check
                        bool allComplete = true;
                        foreach (TellRequestResultPS result in results)
                        {
                            if (result.hasResponded == false)
                                allComplete = false;
                        }
                        //All other servers have already responded, so complete the request
                        if (allComplete == true)
                        {
                            //Pass the request back up to the manager for completion, so it can remove this request from the queue
                            Managers.tellManager.completeRequest(this);
                            return;
                        }
                    }
                }
            }
        }

        private void requestTimeout_Elapsed(object sender, ElapsedEventArgs e)
        {
            //Pass the request back up to the manager for completion, so it can remove this request from the queue
            Managers.tellManager.completeRequest(this);
        }
    }

}
